package interpeter;



import java.lang.reflect.Array;
import java.util.Arrays;

import ic.ast.decl.DeclClass;
import ic.ast.decl.DeclMethod;
import ic.ast.decl.Parameter;
import ic.ast.decl.Program;
import interpeter.REPL.RuntimeError;

/*main lines to run interpeter:
  
 Interpeter interpeter = new Interpeter((Program)ast); 
 Object ob = interpeter.interpetMethod("Class.Method", args, true); // true if libic, false if not libic
 System.out.println( (int)ob) );
 
 */
public class Interpeter {
	
	private REPL repl;	//Read Eval Print Loop 
	private Program programAst;
	
	public Interpeter(Program programAst) {
		repl = new REPL();
		this.programAst = programAst;
	}
	
	public Object interpetMethod(String[] args){
		String methodFullName = args[1];
		String[] method = methodFullName.split("\\.");
		if (method.length == 2){
			String className = method[0];
			String methodName = method[1];
			boolean foundClass = false;
			boolean foundMethod = false;
			int k=-1;
			
			//find class
			for (DeclClass declClass : programAst.getClasses()) {
				if (declClass.getName().equals(className)){
					foundClass = true;
					//find method
					for (DeclMethod declMethod: declClass.getMethods()){
						if (declMethod.getName().equals(methodName)){
							foundMethod = true;
							
							//check proper amount of formals and matched types(only String and Int can pass)
							if (args.length-2 != declMethod.getFormals().size())
								throw new RuntimeError("invalid number of arguments to '"+declMethod.getName()+"'");
							//add activation record
							repl.state.addActivationRecord();
							//add method actual parameters to activation record
							Parameter parameter;
							for (int i = 2; i < args.length ; i++){
								parameter = declMethod.getFormals().get(i-2);
								String typeName = parameter.getType().getDisplayName().toLowerCase();
								if (typeName.equals("int") || typeName.equals("string")){
									//if formal type is int check it can be parsInt-ed
									if (typeName.equals("int")){
											try {k = Integer.parseInt(args[i]);}
											catch (NumberFormatException e){throw new RuntimeError("invalid method parameter");}
									}
									//add entry to activation record
									repl.state.updateVar(parameter.getName(),(typeName.equals("int")? k:args[i]));
								}else{
									throw new RuntimeError("only int or string parameters type allawed");
								}
							}
							//run method body
							try {
								return declMethod.accept(repl);
							}
							catch (RuntimeError e) {
								System.err.println("Run-time error: " + e.getMessage());
							}
						}
					}
				}
			}
			if (foundClass==false) {
				System.err.println("Class " + className +" not found");
			}else if (foundMethod==false){
				System.err.println("Method " + methodName + "not found in Class " + className);
			}
		}else {
			System.err.println("invallid method name");
		}
		return null;
	}
	public void printObject(Object t){
		if (t instanceof Integer){
			System.out.println((Integer)t);
		}else if (t instanceof String){
			System.out.println((Integer)t);
		}else if (t instanceof Boolean){
			System.out.println((Integer)t);
		}else if (t instanceof Object[]){
			Object[] arr = (Object[]) t;
			for (int j = 0; j< arr.length; j++){
				System.out.println(arr[j]);
			}
		}
	}
}
